/*
* Copyright 2010-2015 Institut Pasteur.
*
* This file is part of Icy.
*
* Icy is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Icy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Icy. If not, see <http://www.gnu.org/licenses/>.
*/
package icy.gui.frame;
import icy.action.IcyAbstractAction;
import icy.common.MenuCallback;
import icy.gui.main.MainFrame;
import icy.gui.util.ComponentUtil;
import icy.main.Icy;
import icy.resource.ResourceUtil;
import icy.resource.icon.IcyIcon;
import icy.system.thread.ThreadUtil;
import icy.util.StringUtil;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.ImageObserver;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.WindowConstants;
import javax.swing.border.Border;
import javax.swing.event.EventListenerList;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;
/**
* This class behave either as a JFrame or a JInternalFrame.<br>
* IcyFrame should be 100% AWT safe
*
* @author Fabrice de Chaumont & Stephane Dallongeville
*/
public class IcyFrame implements InternalFrameListener, WindowListener, ImageObserver, PropertyChangeListener
{
private class SwitchStateAction extends IcyAbstractAction
{
/**
*
*/
private static final long serialVersionUID = -4433831471426743128L;
final IcyIcon detachIcon;
final IcyIcon attachIcon;
public SwitchStateAction()
{
super("");
detachIcon = new IcyIcon(ResourceUtil.ICON_WINDOW_EXPAND, 20);
attachIcon = new IcyIcon(ResourceUtil.ICON_WINDOW_COLLAPSE, 20);
setAccelerator(KeyEvent.VK_F3);
refreshState();
}
@Override
public boolean doAction(ActionEvent e)
{
switchState();
return true;
}
void refreshState()
{
if (isInternalized())
{
setName("Detach");
setIcon(detachIcon);
setDescription("Externalize the window");
}
else
{
setName("Attach");
setIcon(attachIcon);
setDescription("Internalize the window");
}
}
}
/**
* list containing all active frames
*/
static ArrayList<IcyFrame> frames = new ArrayList<IcyFrame>();
/**
* Return all active (not closed) IcyFrame
*/
public static ArrayList<IcyFrame> getAllFrames()
{
synchronized (frames)
{
return new ArrayList<IcyFrame>(frames);
}
}
/**
* Return all active IcyFrame which derive from the specified class
*/
public static ArrayList<IcyFrame> getAllFrames(Class<?> frameClass)
{
final ArrayList<IcyFrame> result = new ArrayList<IcyFrame>();
if (frameClass != null)
{
synchronized (frames)
{
for (IcyFrame frame : frames)
if (frameClass.isInstance(frame))
result.add(frame);
}
}
return result;
}
/**
* Find IcyFrame corresponding to the specified JInternalFrame
*/
public static IcyFrame findIcyFrame(JInternalFrame frame)
{
synchronized (frames)
{
for (IcyFrame f : frames)
if (f.getInternalFrame() == frame)
return f;
return null;
}
}
public enum IcyFrameState
{
INTERNALIZED, EXTERNALIZED
}
protected IcyExternalFrame externalFrame;
protected IcyInternalFrame internalFrame;
/**
* frame state (internal / external)
*/
protected IcyFrameState state;
/**
* sync flag for AWT thread process
*/
protected boolean syncProcess;
/**
* listeners
*/
protected EventListenerList frameEventListeners;
/**
* internals
*/
protected final MenuCallback defaultSystemMenuCallback;
protected SwitchStateAction switchStateAction;
protected boolean switchStateItemVisible;
protected IcyFrameState previousState;
public IcyFrame()
{
this("", false, true, false, false, true);
}
public IcyFrame(String title)
{
this(title, false, true, false, false, true);
}
public IcyFrame(String title, boolean resizable)
{
this(title, resizable, true, false, false, true);
}
public IcyFrame(String title, boolean resizable, boolean closable)
{
this(title, resizable, closable, false, false, true);
}
public IcyFrame(String title, boolean resizable, boolean closable, boolean maximizable)
{
this(title, resizable, closable, maximizable, false, true);
}
public IcyFrame(final String title, final boolean resizable, final boolean closable, final boolean maximizable,
final boolean iconifiable)
{
this(title, resizable, closable, maximizable, iconifiable, true);
}
public IcyFrame(final String title, final boolean resizable, final boolean closable, final boolean maximizable,
final boolean iconifiable, final boolean waitCreate)
{
super();
frameEventListeners = new EventListenerList();
defaultSystemMenuCallback = new MenuCallback()
{
@Override
public JMenu getMenu()
{
return getDefaultSystemMenu();
}
};
syncProcess = false;
// set default state
if (canBeInternalized())
state = IcyFrameState.INTERNALIZED;
else
state = IcyFrameState.EXTERNALIZED;
switchStateItemVisible = true;
// wanted default state
previousState = IcyFrameState.INTERNALIZED;
// create action after state has been set
switchStateAction = new SwitchStateAction();
switchStateAction.setEnabled(canBeInternalized());
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
externalFrame = createExternalFrame(title);
// redirect frame / window events
externalFrame.addWindowListener(IcyFrame.this);
externalFrame.setLocationRelativeTo(null);
externalFrame.setResizable(resizable);
externalFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
// default size
externalFrame.setSize(480, 400);
internalFrame = createInternalFrame(title, resizable, closable, maximizable, iconifiable);
// redirect frame / window events
internalFrame.addInternalFrameListener(IcyFrame.this);
// default size
internalFrame.setSize(480, 400);
// default system menu callback
externalFrame.setSystemMenuCallback(defaultSystemMenuCallback);
internalFrame.setSystemMenuCallback(defaultSystemMenuCallback);
// register to the list
synchronized (frames)
{
frames.add(IcyFrame.this);
}
}
}, waitCreate);
final MainFrame mainFrame = Icy.getMainInterface().getMainFrame();
// listen main frame mode change
if (mainFrame != null)
mainFrame.addPropertyChangeListener(MainFrame.PROPERTY_DETACHEDMODE, this);
}
/**
* Permit IcyExternalFrame overriding
*/
protected IcyExternalFrame createExternalFrame(String title)
{
return new IcyExternalFrame(title);
}
/**
* Permit IcyInternalFrame overriding
*/
protected IcyInternalFrame createInternalFrame(String title, boolean resizable, boolean closable,
boolean maximizable, boolean iconifiable)
{
return new IcyInternalFrame(title, resizable, closable, maximizable, iconifiable);
}
/**
* Return true if the frame can be internalized
*/
protected boolean canBeInternalized()
{
final MainFrame frame = Icy.getMainInterface().getMainFrame();
// internalization possible only in single window mode
if (frame != null)
return !frame.isDetachedMode();
return false;
}
/**
* Refresh system menu
*/
public void updateSystemMenu()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.updateSystemMenu();
else
externalFrame.updateSystemMenu();
}
}, syncProcess);
}
/**
* Close frame (send closing event)
*/
public void close()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.close(true);
externalFrame.close();
}
}, syncProcess);
}
/**
* Dispose frame (send closed event)
*/
public void dispose()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.dispose();
else
externalFrame.dispose();
}
}, syncProcess);
}
/** go from detached to attached and opposite */
public void switchState()
{
if (isInternalized())
detach();
else
attach();
}
/** set the frame to be an inner frame on the desktop pane */
public void internalize()
{
if (isExternalized())
attach();
}
/** the frame becomes detached in an independent frame */
public void externalize()
{
if (isInternalized())
detach();
}
/** Set the frame to be an inner frame on the desktop pane */
public void attach()
{
if (isInternalized() || !canBeInternalized())
return;
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
// save current visible state
final boolean visible = externalFrame.isVisible();
// hide external frame
if (visible)
externalFrame.setVisible(false);
final JMenuBar menuBar = externalFrame.getJMenuBar();
final Container content = externalFrame.getContentPane();
// remove components from external frame
externalFrame.setJMenuBar(null);
externalFrame.setContentPane(new JPanel());
externalFrame.validate();
internalFrame.setJMenuBar(menuBar);
internalFrame.setContentPane(content);
internalFrame.validate();
// show internal frame
if (visible)
{
internalFrame.setVisible(true);
try
{
internalFrame.setSelected(true);
}
catch (PropertyVetoException e)
{
// ignore
}
}
state = IcyFrameState.INTERNALIZED;
// notify state change
stateChanged();
}
}, syncProcess);
}
/** Set the frame to be detached in an independent frame */
public void detach()
{
if (isExternalized())
return;
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
// save current visible state
final boolean visible = internalFrame.isVisible();
// hide internal frame
if (visible)
internalFrame.setVisible(false);
final JMenuBar menuBar = internalFrame.getJMenuBar();
final Container content = internalFrame.getContentPane();
// remove components from internal frame
internalFrame.setJMenuBar(null);
internalFrame.setContentPane(new JPanel());
internalFrame.validate();
externalFrame.setJMenuBar(menuBar);
externalFrame.setContentPane(content);
externalFrame.validate();
// show external frame
if (visible)
{
externalFrame.setVisible(true);
externalFrame.requestFocus();
}
// TODO : we have to force a refresh with resizing or we get a refresh bug on
// scrollbar (OSX only ?)
// externalFrame.setSize(externalFrame.getWidth(), externalFrame.getHeight() - 1);
// externalFrame.setSize(externalFrame.getWidth(), externalFrame.getHeight() + 1);
state = IcyFrameState.EXTERNALIZED;
// notify state change
stateChanged();
}
}, syncProcess);
}
/**
* Called on state (internalized / externalized) change
*/
public void stateChanged()
{
// refresh switch action state
switchStateAction.refreshState();
// refresh system menu
updateSystemMenu();
// fire event
if (isInternalized())
fireFrameInternalized(new IcyFrameEvent(IcyFrame.this, null, null));
else
fireFrameExternalized(new IcyFrameEvent(IcyFrame.this, null, null));
}
/** Center frame on the desktop */
public void center()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
ComponentUtil.center(internalFrame);
else
ComponentUtil.center(externalFrame);
}
}, syncProcess);
}
/**
* Add to the container c
*/
public void addTo(final Container c)
{
if (isInternalized())
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
c.add(internalFrame);
}
}, syncProcess);
}
}
/**
* Add to the container c
*/
public void addTo(final Container c, final int index)
{
if (isInternalized())
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
c.add(internalFrame, index);
}
}, syncProcess);
}
}
/**
* @deprecated Use {@link #addToDesktopPane()} instead.
*/
@Deprecated
public void addTo(final Container c, final Object constraints)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
c.add(internalFrame, constraints);
}
}, syncProcess);
}
/**
* Add the frame to the Icy desktop pane with specified constraint.
*/
public void addToDesktopPane(final Object constraints)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
final JDesktopPane desktop = Icy.getMainInterface().getDesktopPane();
if (desktop != null)
desktop.add(internalFrame, constraints);
}
}, syncProcess);
}
/**
* Add the frame to the Icy desktop pane
*/
public void addToDesktopPane()
{
addToDesktopPane(JLayeredPane.DEFAULT_LAYER);
}
/**
* @deprecated Use {@link #addToDesktopPane()} instead.
*/
@Deprecated
public void addToMainDesktopPane()
{
addToDesktopPane();
}
/**
* Implement add method
*/
public void add(final Component comp)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.add(comp);
else
externalFrame.add(comp);
}
}, syncProcess);
}
/**
* Implement add method
*/
public void add(final Component comp, final Object constraints)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.add(comp, constraints);
else
externalFrame.add(comp, constraints);
}
}, syncProcess);
}
/**
* Implement add method
*/
public void add(final String name, final Component comp)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.add(name, comp);
else
externalFrame.add(name, comp);
}
}, syncProcess);
}
/**
* Remove from the container
*/
public void removeFrom(final Container c)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
c.remove(internalFrame);
}
}, syncProcess);
}
/**
* Implement removeAll method
*/
public void removeAll()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.removeAll();
else
externalFrame.removeAll();
}
}, syncProcess);
}
/**
* Implement remove method
*/
public void remove(final Component comp)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.remove(comp);
else
externalFrame.remove(comp);
}
}, syncProcess);
}
/**
* Remove the frame from the main pane of ICY
*/
public void removeFromMainDesktopPane()
{
removeFrom(Icy.getMainInterface().getDesktopPane());
}
/**
* Implement toFront method
*/
public void toFront()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.toFront();
else
externalFrame.toFront();
}
}, syncProcess);
}
/**
* Implement toBack method
*/
public void toBack()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.toBack();
else
externalFrame.toBack();
}
}, syncProcess);
}
/**
* Implement pack method
*/
public void pack()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.pack();
else
externalFrame.pack();
}
}, syncProcess);
}
public Container getFrame()
{
if (isInternalized())
return internalFrame;
return externalFrame;
}
public IcyInternalFrame getIcyInternalFrame()
{
return internalFrame;
}
public IcyExternalFrame getIcyExternalFrame()
{
return externalFrame;
}
public JInternalFrame getInternalFrame()
{
return internalFrame;
}
public JFrame getExternalFrame()
{
return externalFrame;
}
/**
* Indicate if system menu show display item to switch frame state (internal / external)
*/
public void setSwitchStateItemVisible(boolean value)
{
if (switchStateItemVisible != value)
{
switchStateItemVisible = value;
switchStateAction.setEnabled(value);
updateSystemMenu();
}
}
/**
* @return the systemMenuCallback
*/
public MenuCallback getSystemMenuCallback()
{
// always have same callback on each frame
final MenuCallback result = internalFrame.getSystemMenuCallback();
// default callback ? this means we set it to null
if (result == defaultSystemMenuCallback)
return null;
return result;
}
/**
* Set the system menu callback (this allow modification of system menu)
*
* @param value
* the systemMenuCallback to set
*/
public void setSystemMenuCallback(MenuCallback value)
{
if (value != null)
{
internalFrame.setSystemMenuCallback(value);
externalFrame.setSystemMenuCallback(value);
}
else
{
internalFrame.setSystemMenuCallback(defaultSystemMenuCallback);
externalFrame.setSystemMenuCallback(defaultSystemMenuCallback);
}
}
/**
* Return the default system menu
*/
public JMenu getDefaultSystemMenu()
{
final JMenu result;
if (isInternalized())
result = internalFrame.getDefaultSystemMenu();
else
result = externalFrame.getDefaultSystemMenu();
if (switchStateItemVisible)
{
result.insert(switchStateAction, 0);
if (result.getMenuComponentCount() > 1)
result.insertSeparator(1);
}
return result;
}
/**
* Implement getParent
*/
public Container getParent()
{
if (isInternalized())
return internalFrame.getParent();
return externalFrame.getParent();
}
/**
* Implement getContentPane method
*/
public Container getContentPane()
{
if (isInternalized())
return internalFrame.getContentPane();
return externalFrame.getContentPane();
}
/**
* Implement getRootPane method
*/
public JRootPane getRootPane()
{
if (isInternalized())
return internalFrame.getRootPane();
return externalFrame.getRootPane();
}
/**
* @return the switchStateAction
*/
public SwitchStateAction getSwitchStateAction()
{
return switchStateAction;
}
/**
* Implement getMinimumSize method
*/
public Dimension getMinimumSize()
{
if (isInternalized())
return internalFrame.getMinimumSize();
return externalFrame.getMinimumSize();
}
/**
* Implement getMinimumSize method for internal frame only
*/
public Dimension getMinimumSizeInternal()
{
return internalFrame.getMinimumSize();
}
/**
* Implement getMinimumSize method for external frame only
*/
public Dimension getMinimumSizeExternal()
{
return externalFrame.getMinimumSize();
}
/**
* Implement getMaximumSize method
*/
public Dimension getMaximumSize()
{
if (isInternalized())
return internalFrame.getMaximumSize();
return externalFrame.getMaximumSize();
}
/**
* Implement getMaximumSize method for internal frame only
*/
public Dimension getMaximumSizeInternal()
{
return internalFrame.getMaximumSize();
}
/**
* Implement getMaximumSize method for external frame only
*/
public Dimension getMaximumSizeExternal()
{
return externalFrame.getMaximumSize();
}
/**
* Implement getPreferredSize method
*/
public Dimension getPreferredSize()
{
if (isInternalized())
return internalFrame.getPreferredSize();
return externalFrame.getPreferredSize();
}
/**
* Implement getPreferredSize method for internal frame only
*/
public Dimension getPreferredSizeInternal()
{
return internalFrame.getPreferredSize();
}
/**
* Implement getPreferredSize method for external frame only
*/
public Dimension getPreferredSizeExternal()
{
return externalFrame.getPreferredSize();
}
/**
* Implement getSize method
*/
public Dimension getSize()
{
if (isInternalized())
return internalFrame.getSize();
return externalFrame.getSize();
}
/**
* Implement getSize method for internal frame only
*/
public Dimension getSizeInternal()
{
return internalFrame.getSize();
}
/**
* Implement getSize method for external frame only
*/
public Dimension getSizeExternal()
{
return externalFrame.getSize();
}
/**
* Implement getHeight method
*/
public int getHeight()
{
if (isInternalized())
return internalFrame.getHeight();
return externalFrame.getHeight();
}
/**
* Implement getHeight method for internal frame only
*/
public int getHeightInternal()
{
return internalFrame.getHeight();
}
/**
* Implement getHeight method for external frame only
*/
public int getHeightExternal()
{
return externalFrame.getHeight();
}
/**
* Implement getWidth method
*/
public int getWidth()
{
if (isInternalized())
return internalFrame.getWidth();
return externalFrame.getWidth();
}
/**
* Implement getWidth method for internal frame only
*/
public int getWidthInternal()
{
return internalFrame.getWidth();
}
/**
* Implement getWidth method for external frame only
*/
public int getWidthExternal()
{
return externalFrame.getWidth();
}
/**
* Implement getX method
*/
public int getX()
{
if (isInternalized())
return internalFrame.getX();
return externalFrame.getX();
}
/**
* Implement getX method for internal frame only
*/
public int getXInternal()
{
return internalFrame.getX();
}
/**
* Implement getX method for external frame only
*/
public int getXExternal()
{
return externalFrame.getX();
}
/**
* Implement getY method
*/
public int getY()
{
if (isInternalized())
return internalFrame.getY();
return externalFrame.getY();
}
/**
* Implement getY method for internal frame only
*/
public int getYInternal()
{
return internalFrame.getY();
}
/**
* Implement getY method for external frame only
*/
public int getYExternal()
{
return externalFrame.getY();
}
/**
* Implement getLocation method
*/
public Point getLocation()
{
if (isInternalized())
return internalFrame.getLocation();
return externalFrame.getLocation();
}
/**
* Implement getLocation method
*/
public Point getLocationInternal()
{
return internalFrame.getLocation();
}
/**
* Implement getLocation method for external frame only
*/
public Point getLocationExternal()
{
return externalFrame.getLocation();
}
/**
* Implement getBounds method
*/
public Rectangle getBounds()
{
if (isInternalized())
return internalFrame.getBounds();
return externalFrame.getBounds();
}
/**
* Implement getBounds method for internal frame only
*/
public Rectangle getBoundsInternal()
{
return internalFrame.getBounds();
}
/**
* Implement getBounds method for external frame only
*/
public Rectangle getBoundsExternal()
{
return externalFrame.getBounds();
}
/**
* Implement getBounds method for external frame only
*/
public Rectangle getVisibleRect()
{
if (isInternalized())
return internalFrame.getVisibleRect();
// not supported on external frame
if (externalFrame.isVisible())
return externalFrame.getBounds();
return new Rectangle();
}
/**
* Implement getJMenuBar method
*/
public JMenuBar getJMenuBar()
{
if (isInternalized())
return internalFrame.getJMenuBar();
return externalFrame.getJMenuBar();
}
/**
* Returns the content pane InputMap
*/
public InputMap getInputMap(int condition)
{
if (isInternalized())
return ((JPanel) internalFrame.getContentPane()).getInputMap(condition);
return ((JPanel) externalFrame.getContentPane()).getInputMap(condition);
}
/**
* Returns the content pane InputMap
*/
public ActionMap getActionMap()
{
if (isInternalized())
return ((JPanel) internalFrame.getContentPane()).getActionMap();
return ((JPanel) externalFrame.getContentPane()).getActionMap();
}
/**
* Implement getToolkit method
*/
public Toolkit getToolkit()
{
if (isInternalized())
return internalFrame.getToolkit();
return externalFrame.getToolkit();
}
/**
* Implement setTitle method
*/
public String getTitle()
{
if (isInternalized())
return internalFrame.getTitle();
return externalFrame.getTitle();
}
/**
* Return true if title bar is visible
*/
public boolean getTitleBarVisible()
{
if (isInternalized())
return internalFrame.isTitleBarVisible();
return externalFrame.isTitleBarVisible();
}
/**
* @return the displaySwitchStateItem
*/
public boolean isSwitchStateItemVisible()
{
return switchStateItemVisible;
}
/**
* Implement getMousePosition method
*/
public Point getMousePosition()
{
if (isInternalized())
return internalFrame.getMousePosition();
return externalFrame.getMousePosition();
}
/**
* Implement isMinimized method
*/
public boolean isMinimized()
{
if (isInternalized())
return internalFrame.isIcon();
return ComponentUtil.isMinimized(externalFrame);
}
/**
* Implement isMinimized method for internal frame only
*/
public boolean isMinimizedInternal()
{
return internalFrame.isIcon();
}
/**
* Implement isMinimized method for external frame only
*/
public boolean isMinimizedExternal()
{
return ComponentUtil.isMinimized(externalFrame);
}
/**
* Implement isMaximized method
*/
public boolean isMaximized()
{
if (isInternalized())
return internalFrame.isMaximum();
return ComponentUtil.isMaximized(externalFrame);
}
/**
* Implement isMaximized method for internal frame only
*/
public boolean isMaximizedInternal()
{
return internalFrame.isMaximum();
}
/**
* Implement isMaximized method for external frame only
*/
public boolean isMaximizedExternal()
{
return ComponentUtil.isMaximized(externalFrame);
}
/**
* Implement isVisible method
*/
public boolean isVisible()
{
if (isInternalized())
return internalFrame.isVisible();
return externalFrame.isVisible();
}
/**
* Implement isResizable method
*/
public boolean isResizable()
{
if (isInternalized())
return internalFrame.isResizable();
return externalFrame.isResizable();
}
/**
* Implement isClosable method
*/
public boolean isClosable()
{
if (isInternalized())
return internalFrame.isClosable();
// external frame is always closable
return true;
}
/**
* return true if frame is in internalized state
*/
public boolean isInternalized()
{
return (state == IcyFrameState.INTERNALIZED);
}
/**
* return true if frame is in externalized state
*/
public boolean isExternalized()
{
return (state == IcyFrameState.EXTERNALIZED);
}
/**
* return true if frame is active
*/
public boolean isActive()
{
if (isInternalized())
return internalFrame.isSelected();
return externalFrame.isActive();
}
/**
* Implement isAlwaysOnTop method (only for externalized frame)
*/
public boolean isAlwaysOnTop()
{
return externalFrame.isAlwaysOnTop();
}
/**
* Implement hasFocus method
*/
public boolean hasFocus()
{
if (isInternalized())
return internalFrame.hasFocus();
return externalFrame.hasFocus();
}
/**
* Implement setTitle method
*/
public void setTitle(final String title)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setTitle(title);
externalFrame.setTitle(title);
}
}, syncProcess);
}
/**
* Implement setToolTipText method (only for internalized frame)
*/
public void setToolTipText(final String text)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
// only internal frame support it
internalFrame.setToolTipText(text);
// externalFrame.setToolTipText(text);
}
}, syncProcess);
}
/**
* Implement setBackground method
*/
public void setBackground(final Color value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setBackground(value);
externalFrame.setBackground(value);
}
}, syncProcess);
}
/**
* Implement setForeground method
*/
public void setForeground(final Color value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setForeground(value);
externalFrame.setForeground(value);
}
}, syncProcess);
}
/**
* Implement setResizable method
*/
public void setResizable(final boolean value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setResizable(value);
externalFrame.setResizable(value);
}
}, syncProcess);
}
/**
* Implement setLocation method
*/
public void setLocation(final Point p)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setLocation(p);
else
externalFrame.setLocation(p);
}
}, syncProcess);
}
/**
* Implement setLocation method
*/
public void setLocation(final int x, final int y)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setLocation(x, y);
else
externalFrame.setLocation(x, y);
}
}, syncProcess);
}
/**
* Implement setLocation method for internal frame only
*/
public void setLocationInternal(final Point p)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setLocation(p);
}
}, syncProcess);
}
/**
* Implement setLocation method for internal frame only
*/
public void setLocationInternal(final int x, final int y)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setLocation(x, y);
}
}, syncProcess);
}
/**
* Implement setLocation method for external frame only
*/
public void setLocationExternal(final Point p)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
externalFrame.setLocation(p);
}
}, syncProcess);
}
/**
* Implement setLocation method for external frame only
*/
public void setLocationExternal(final int x, final int y)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
externalFrame.setLocation(x, y);
}
}, syncProcess);
}
/**
* Implement setSize method
*/
public void setSize(final Dimension d)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setSize(d);
else
externalFrame.setSize(d);
}
}, syncProcess);
}
/**
* Implement setSize method
*/
public void setSize(final int width, final int height)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setSize(width, height);
else
externalFrame.setSize(width, height);
}
}, syncProcess);
}
/**
* Implement setSize method for internal frame only
*/
public void setSizeInternal(final Dimension d)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setSize(d);
}
}, syncProcess);
}
/**
* Implement setSize method for internal frame only
*/
public void setSizeInternal(final int width, final int height)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setSize(width, height);
}
}, syncProcess);
}
/**
* Implement setSize method for external frame only
*/
public void setSizeExternal(final Dimension d)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
externalFrame.setSize(d);
}
}, syncProcess);
}
/**
* Implement setSize method for external frame only
*/
public void setSizeExternal(final int width, final int height)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
externalFrame.setSize(width, height);
}
}, syncProcess);
}
/**
* Implement setPreferredSize method
*/
public void setPreferredSize(final Dimension d)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setPreferredSize(d);
else
externalFrame.setPreferredSize(d);
}
}, syncProcess);
}
/**
* Implement setPreferredSize method for internal frame only
*/
public void setPreferredSizeInternal(final Dimension d)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setPreferredSize(d);
}
}, syncProcess);
}
/**
* Implement setPreferredSize method for external frame only
*/
public void setPreferredSizeExternal(final Dimension d)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
externalFrame.setPreferredSize(d);
}
}, syncProcess);
}
/**
* Implement setMinimumSize method
*/
public void setMinimumSize(final Dimension d)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setMinimumSize(d);
else
externalFrame.setMinimumSize(d);
}
}, syncProcess);
}
/**
* Implement setMaximumSize method
*/
public void setMaximumSize(final Dimension d)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setMaximumSize(d);
else
externalFrame.setMaximumSize(d);
}
}, syncProcess);
}
/**
* Implement setMinimumSize method for internal frame only
*/
public void setMinimumSizeInternal(final Dimension d)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setMinimumSize(d);
}
}, syncProcess);
}
/**
* Implement setMaximumSize method for internal frame only
*/
public void setMaximumSizeInternal(final Dimension d)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setMaximumSize(d);
}
}, syncProcess);
}
/**
* Implement setMinimumSize method for external frame only
*/
public void setMinimumSizeExternal(final Dimension d)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
externalFrame.setMinimumSize(d);
}
}, syncProcess);
}
/**
* Implement setMaximumSize method for external frame only
*/
public void setMaximumSizeExternal(final Dimension d)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
externalFrame.setMaximumSize(d);
}
}, syncProcess);
}
/**
* Implement setBounds method
*/
public void setBounds(final Rectangle r)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setBounds(r);
else
externalFrame.setBounds(r);
}
}, syncProcess);
}
/**
* Implement setMaximisable method
*/
public void setMaximisable(final boolean value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
// only for internal frame
internalFrame.setMaximizable(value);
}
}, syncProcess);
}
/**
* Implement setMinimized method
*/
public void setMinimized(final boolean value)
{
// only relevant if state changed
if (isMinimized() ^ value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setMinimized(value);
else
externalFrame.setMinimized(value);
}
}, syncProcess);
}
}
/**
* Implement setMinimized method for internal frame only
*/
public void setMinimizedInternal(final boolean value)
{
// only relevant if state changed
if (internalFrame.isMinimized() ^ value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setMinimized(value);
}
}, syncProcess);
}
}
/**
* Implement setMinimized method for external frame only
*/
public void setMinimizedExternal(final boolean value)
{
// only relevant if state changed
if (externalFrame.isMinimized() ^ value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
externalFrame.setMinimized(value);
}
}, syncProcess);
}
}
/**
* Implement setMaximized method
*/
public void setMaximized(final boolean value)
{
// only relevant if state changed
if (isMaximized() ^ value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setMaximized(value);
else
externalFrame.setMaximized(value);
}
}, syncProcess);
}
}
/**
* Implement setMaximized method for internal frame only
*/
public void setMaximizedInternal(final boolean value)
{
// only relevant if state changed
if (internalFrame.isMaximized() ^ value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setMaximized(value);
}
}, syncProcess);
}
}
/**
* Implement setMaximized method for external frame only
*/
public void setMaximizedExternal(final boolean value)
{
// only relevant if state changed
if (externalFrame.isMaximized() ^ value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
externalFrame.setMaximized(value);
}
}, syncProcess);
}
}
/**
* Implement setClosable method
*/
public void setClosable(final boolean value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setClosable(value);
}
}, syncProcess);
}
/**
* Implement setDefaultCloseOperation method
*
* @see JFrame#setDefaultCloseOperation(int)
*/
public void setDefaultCloseOperation(final int operation)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setDefaultCloseOperation(operation);
externalFrame.setDefaultCloseOperation(operation);
}
}, syncProcess);
}
/**
* Implement setFocusable method
*/
public void setFocusable(final boolean value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setFocusable(value);
externalFrame.setFocusable(value);
}
}, syncProcess);
}
/**
* Implement setVisible method
*/
public void setVisible(final boolean value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setVisible(value);
else
externalFrame.setVisible(value);
}
}, syncProcess);
}
/**
* Implement setAlwaysOnTop method (only for externalized frame)
*/
public void setAlwaysOnTop(final boolean alwaysOnTop)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
externalFrame.setAlwaysOnTop(alwaysOnTop);
}
}, syncProcess);
}
/**
* Implement setJMenuBar method
*/
public void setJMenuBar(final JMenuBar m)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setJMenuBar(m);
else
externalFrame.setJMenuBar(m);
}
}, syncProcess);
}
/**
* Hide or show the title bar (frame should not be displayable when you set this property)
*/
public void setTitleBarVisible(final boolean value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setTitleBarVisible(value);
externalFrame.setTitleBarVisible(value);
}
}, syncProcess);
}
/**
* Implement setLayout method
*/
public void setLayout(final LayoutManager layout)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setLayout(layout);
else
externalFrame.setLayout(layout);
}
}, syncProcess);
}
/**
* Implement setBorder method (only for internal frame)
*/
public void setBorder(final Border border)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.setBorder(border);
}
}, syncProcess);
}
/**
* Implement setContentPane method
*/
public void setContentPane(final Container value)
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.setContentPane(value);
else
externalFrame.setContentPane(value);
}
}, syncProcess);
}
/**
* @return the syncProcess
*/
public boolean isSyncProcess()
{
return syncProcess;
}
/**
* By default IcyFrame does asych processing, you can force sync processing<br>
* with this property
*
* @param syncProcess
* the syncProcess to set
*/
public void setSyncProcess(boolean syncProcess)
{
this.syncProcess = syncProcess;
}
/**
* Frame becomes the active/focused frame
*/
public void requestFocus()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
{
try
{
internalFrame.setSelected(true);
}
catch (PropertyVetoException e)
{
// ignore
}
}
else
externalFrame.requestFocus();
}
}, syncProcess);
}
/**
* Implement validate
*/
public void validate()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.validate();
else
externalFrame.validate();
}
}, syncProcess);
}
/**
* Implement revalidate
*/
public void revalidate()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.revalidate();
else
{
externalFrame.invalidate();
externalFrame.repaint();
}
}
}, syncProcess);
}
/**
* Implement repaint
*/
public void repaint()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
if (isInternalized())
internalFrame.repaint();
else
externalFrame.repaint();
}
}, syncProcess);
}
/**
* Implement updateUI
*/
public void updateUI()
{
// AWT safe
ThreadUtil.invoke(new Runnable()
{
@Override
public void run()
{
internalFrame.updateUI();
}
}, syncProcess);
}
/**
* Fire frame activated event
*/
private void fireFrameActivated(IcyFrameEvent e)
{
for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
l.icyFrameActivated(e);
}
/**
* Fire frame deactivated event
*/
private void fireFrameDeactivated(IcyFrameEvent e)
{
for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
l.icyFrameDeactivated(e);
}
/**
* Fire frame closing event
*/
private void fireFrameClosing(IcyFrameEvent e)
{
for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
l.icyFrameClosing(e);
}
/**
* Fire frame closed event
*/
private void fireFrameClosed(IcyFrameEvent e)
{
for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
l.icyFrameClosed(e);
}
/**
* Fire frame iconified event
*/
private void fireFrameIconified(IcyFrameEvent e)
{
for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
l.icyFrameIconified(e);
}
/**
* Fire frame deiconified event
*/
private void fireFrameDeiconified(IcyFrameEvent e)
{
for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
l.icyFrameDeiconified(e);
}
/**
* Fire frame opened event
*/
private void fireFrameOpened(IcyFrameEvent e)
{
for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
l.icyFrameOpened(e);
}
/**
* Fire frame internalized event
*/
void fireFrameInternalized(IcyFrameEvent e)
{
for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
l.icyFrameInternalized(e);
}
/**
* Fire frame externalized event
*/
void fireFrameExternalized(IcyFrameEvent e)
{
for (IcyFrameListener l : frameEventListeners.getListeners(IcyFrameListener.class))
l.icyFrameExternalized(e);
}
/**
* Implement addFrameListener method
*/
public void addFrameListener(IcyFrameListener l)
{
frameEventListeners.add(IcyFrameListener.class, l);
}
/**
* Implement removeFrameListener method
*/
public void removeFrameListener(IcyFrameListener l)
{
frameEventListeners.remove(IcyFrameListener.class, l);
}
/**
* Implement addComponentListener method
*/
public void addComponentListener(ComponentListener l)
{
internalFrame.addComponentListener(l);
externalFrame.addComponentListener(l);
}
/**
* Implement removeComponentListener method
*/
public void removeComponentListener(ComponentListener l)
{
internalFrame.removeComponentListener(l);
externalFrame.removeComponentListener(l);
}
/**
* Implement addKeyListener method
*/
public void addKeyListener(KeyListener l)
{
internalFrame.addKeyListener(l);
externalFrame.addKeyListener(l);
}
/**
* Implement addKeyListener method
*/
public void removeKeyListener(KeyListener l)
{
internalFrame.removeKeyListener(l);
externalFrame.removeKeyListener(l);
}
/**
* internal close stuff
*/
public void frameClosed(AWTEvent e)
{
final MainFrame mainFrame = Icy.getMainInterface().getMainFrame();
// remove listener on main frame mode change
if (mainFrame != null)
mainFrame.removePropertyChangeListener(MainFrame.PROPERTY_DETACHEDMODE, this);
// remove others listeners
externalFrame.removeWindowListener(IcyFrame.this);
internalFrame.removeInternalFrameListener(IcyFrame.this);
if (e instanceof InternalFrameEvent)
{
fireFrameClosed(new IcyFrameEvent(this, (InternalFrameEvent) e, null));
// don't forget to close external frame
externalFrame.dispose();
}
else if (e instanceof WindowEvent)
{
fireFrameClosed(new IcyFrameEvent(this, null, (WindowEvent) e));
// don't forget to close internal frame
internalFrame.dispose();
}
// easy onClosed handling
onClosed();
}
/**
* easy onClosed job
*/
public void onClosed()
{
// unregister from list
synchronized (frames)
{
frames.remove(this);
}
// release some stuff else we have cycling reference
externalFrame.systemMenuCallback = null;
internalFrame.systemMenuCallback = null;
switchStateAction = null;
}
@Override
public void internalFrameActivated(InternalFrameEvent e)
{
fireFrameActivated(new IcyFrameEvent(this, e, null));
}
@Override
public void internalFrameClosed(InternalFrameEvent e)
{
frameClosed(e);
}
@Override
public void internalFrameClosing(InternalFrameEvent e)
{
fireFrameClosing(new IcyFrameEvent(this, e, null));
}
@Override
public void internalFrameDeactivated(InternalFrameEvent e)
{
fireFrameDeactivated(new IcyFrameEvent(this, e, null));
}
@Override
public void internalFrameDeiconified(InternalFrameEvent e)
{
fireFrameDeiconified(new IcyFrameEvent(this, e, null));
}
@Override
public void internalFrameIconified(InternalFrameEvent e)
{
fireFrameIconified(new IcyFrameEvent(this, e, null));
}
@Override
public void internalFrameOpened(InternalFrameEvent e)
{
fireFrameOpened(new IcyFrameEvent(this, e, null));
}
@Override
public void windowActivated(WindowEvent e)
{
fireFrameActivated(new IcyFrameEvent(this, null, e));
}
@Override
public void windowClosed(WindowEvent e)
{
frameClosed(e);
}
@Override
public void windowClosing(WindowEvent e)
{
fireFrameClosing(new IcyFrameEvent(this, null, e));
}
@Override
public void windowDeactivated(WindowEvent e)
{
fireFrameDeactivated(new IcyFrameEvent(this, null, e));
}
@Override
public void windowDeiconified(WindowEvent e)
{
fireFrameDeiconified(new IcyFrameEvent(this, null, e));
}
@Override
public void windowIconified(WindowEvent e)
{
fireFrameIconified(new IcyFrameEvent(this, null, e));
}
@Override
public void windowOpened(WindowEvent e)
{
fireFrameOpened(new IcyFrameEvent(this, null, e));
}
@Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
{
if (isInternalized())
return internalFrame.imageUpdate(img, infoflags, x, y, width, height);
return externalFrame.imageUpdate(img, infoflags, x, y, width, height);
}
@Override
public void propertyChange(PropertyChangeEvent evt)
{
if (StringUtil.equals(evt.getPropertyName(), MainFrame.PROPERTY_DETACHEDMODE))
{
// window mode has been changed
final boolean detachedMode = ((Boolean) evt.getNewValue()).booleanValue();
// detached mode set --> externalize
if (detachedMode)
{
// save previous state
previousState = state;
externalize();
// disable switch state item
if (switchStateAction != null)
switchStateAction.setEnabled(false);
}
else
{
// restore previous state
if (previousState == IcyFrameState.INTERNALIZED)
internalize();
// enable switch state item
if (switchStateAction != null)
switchStateAction.setEnabled(true);
}
}
}
}